import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.builder.CustomFile;
import com.baomidou.mybatisplus.generator.config.converts.FirebirdTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
import org.apache.ibatis.type.JdbcType;

import java.io.File;
import java.util.*;

/**
 * @class: Generator
 * @description:
 * @author: fs
 * @create: 2023/11/11 20:53
 **/
public class Generator {
    static String outputDir = System.getProperty("user.dir");//指定输出目录
    static String parent = "com.ds";
    static String moduleName = "console";

    static String commonPath = "./ds-admin/src/main/java/com/ds/console/";

    public static void main(String[] args) {
        String url = "jdbc:mysql://124.70.182.205:9001/fs?characterEncoding=utf-8&autoReconnect=true" +
                "&allowMultiQueries=true&noAccessToProcedureBodies=true&serverTimezone=GMT%2B8&useSSL=false";//数据库url
        String username = "root";//账号
        String password = "Admin123@";//密码
        new AutoGenerator(dataSourceConfig(url, username, password))
                // 全局配置
                .global(globalConfig())
                // 包配置
                .packageInfo(packageConfig())
                // 策略配置
                .strategy(strategyConfig())
                // 注入配置
                .injection(injectionConfig())
                // 执行
                .execute();
    }

    private static DataSourceConfig dataSourceConfig(String url, String username, String password) {
        return new DataSourceConfig.Builder(url, username, password).typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
            // 兼容旧版本转换成Integer
            if (JdbcType.BIT == metaInfo.getJdbcType()) {
                return DbColumnType.INTEGER;
            }
            return typeRegistry.getColumnType(metaInfo);
        }).build();
    }

    private static PackageConfig packageConfig() {

        // 设置自定义路径
        Map<OutputFile, String> pathInfo = new HashMap<>();
        pathInfo.put(OutputFile.controller, commonPath + "controller");
        pathInfo.put(OutputFile.serviceImpl, commonPath + "service");
        pathInfo.put(OutputFile.entity, commonPath + "entity");
        pathInfo.put(OutputFile.mapper, commonPath + "mapper");
        pathInfo.put(OutputFile.xml, commonPath + "mapper" + File.separator + "xml");
        return new PackageConfig.Builder()
                .parent(parent)
                .moduleName(moduleName)
                .entity("entity")
                //.service("service")
                .serviceImpl("service")
                .mapper("mapper")
                .xml("mapper.xml")
                .controller("controller")
                .pathInfo(pathInfo)
                .build();
    }


    private static GlobalConfig globalConfig() {
        return new GlobalConfig.Builder()
                .outputDir(outputDir)
                .author("fusheng")
                .enableSpringdoc()
                .disableOpenDir()
                .dateType(DateType.ONLY_DATE)
                .commentDate("yyyy-MM-dd")
                .build();
    }

    private static StrategyConfig strategyConfig() {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入表名，多个英文逗号分隔？所有输入 all");
        return new StrategyConfig.Builder().addInclude(getTables(scanner.nextLine()))
                                           //开启生成实体类
                                           .entityBuilder()
                                           //.enableFileOverride()
                                           .enableLombok()//开启 lombok 模型
                                           .enableChainModel() // 开启链式模式
                                           .javaTemplate("/templates/entity.java.vm")

                                           //开启生成mapper
                                           .mapperBuilder()
                                           .enableBaseResultMap()//启用 BaseResultMap 生成
                                           .mapperAnnotation(org.apache.ibatis.annotations.Mapper.class)//开启 @Mapper 注解
                                           .formatMapperFileName("%sMapper")//格式化 mapper 文件名称
                                           .formatXmlFileName("%sMapper")//格式化 xml 实现类文件名称
                                           .mapperTemplate("/templates/mapper.java.vm")
                                           .mapperXmlTemplate("/templates/mapper.xml.vm")
                                           //.enableFileOverride()

                                           .serviceBuilder()
                                           .formatServiceImplFileName("%sService")
                                           .serviceImplTemplate("/templates/service.java.vm")
                                           .disableService()

                                           .controllerBuilder()
                                           .enableRestStyle()
                                           .template("/templates/controller.java.vm")
                                           .build();
    }

    private static InjectionConfig injectionConfig() {
        return new InjectionConfig.Builder().beforeOutputFile((tableInfo, objectMap) -> {
                                                String entityName = tableInfo.getEntityName();
                                                // 自定义属性
                                                objectMap.put("camelName", entityName.substring(0, 1).toLowerCase() + entityName.substring(1));
                                                objectMap.put("voPath", parent + "." + moduleName + ".vo");
                                                objectMap.put("boPath", parent + "." + moduleName + ".bo");
                                                ConfigBuilder config = (ConfigBuilder) objectMap.get("config");
                                                TableField primaryFiled = tableInfo.getFields().stream().filter(TableField::isKeyFlag).findAny().orElse(tableInfo.getFields().get(0));
                                                IColumnType dateTimeType = FirebirdTypeConvert.toDateType(config.getGlobalConfig(), "");
                                                IColumnType dateType = FirebirdTypeConvert.toDateType(config.getGlobalConfig(), "date");
                                                objectMap.put("datePackage", new HashSet<>(List.of(dateTimeType.getPkg(), dateType.getPkg())));
                                                objectMap.put("primaryFiled", primaryFiled);
                                                System.out.println(JSONUtil.toJsonStr(objectMap));
                                            }).customFile(new CustomFile.Builder()
                                                    .fileName("Vo.java")
                                                    .templatePath("templates/vo.java.vm")
                                                    .packageName("vo")
                                                    .filePath(commonPath)
                                                    .enableFileOverride()
                                                    .build())
                                            .customFile(new CustomFile.Builder()
                                                    .fileName("Bo.java")
                                                    .templatePath("templates/bo.java.vm")
                                                    .packageName("bo")
                                                    .filePath(commonPath)
                                                    .enableFileOverride()
                                                    .build())
                                            .build();
    }

    protected static List<String> getTables(String tables) {
        return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));
    }

}
